<?php
/*
Plugin Name: Open Scriptures Delicious Links
Description: Mashes up WordPress Links with Delicious data so that they can be more useful and viewed in more ways (e.g. tag cloud).
Version: 0.1
Author: Weston Ruter
Author URI: http://weston.ruter.net/
Copyright: 2009, Open Scriptures. GPL 3.0 License.
*/

add_option('delinks_previous_link_id_fetched', 0);
add_option('delinks_cron_registered', false);
add_option('delinks_page_id', 126);

/**
 * Setup plugin
 */
if(!get_option('delinks_cron_registered')){
	wp_schedule_single_event( 0, 'delinks_cron_update');
	update_option('delinks_cron_registered', true);
}

/**
 * Init the plugin
 */
//function delinks_init(){
//	remove_filter('pre_link_description', 'wp_filter_kses');
//}
//add_action('init', 'delinks_init');

/**
 * @global $delinks_ordering_info Contains orderby defaults info; array key is 
 */
$delinks_ordering_info = array(
	'name' => array(
		'sort_column' => 'link_name',
		'name' => 'Name',
		'orderdir' => 'asc'
	),
	'popularity' => array(
		'sort_column' => 'post_count',
		'name' => 'Popularity',
		'orderdir' => 'desc'
	),
	'created' => array(
		'sort_column' => $wpdb->links.'.link_id',
		'name' => 'Age',
		'orderdir' => 'desc'
	)
);

/**
 * Get the current page's link orderby 
 */
function delinks_get_orderby(){
	static $orderby = null;
	if($orderby)
		return $orderby;
	
	//Default
	$orderby = 'name';
	
	//Specified in query
	if(!empty($_GET['orderby']))
		$orderby = strtolower($_GET['orderby']);
	
	return $orderby;
}

/**
 * Get the WordPress links mashed up with the delicious data
 */
function get_delinks(){
	global $wpdb, $delinks_ordering_info;
	
	$sql = "SELECT DISTINCT $wpdb->links.*, delicious_bookmarks.* FROM $wpdb->links";
	
	$orderby = '';
	$orderdir = '';
	$limit = '';
	
	$wpdb->show_errors();
	
	$wheres = array();
	$tags = get_query_var('delicious_tags');
	if(!empty($tags)){
		$tagConds = array();
		foreach($tags as $tag){
			$tagConds[] = '"' . mysql_real_escape_string($tag) . '"';
		}
		$sql .= " INNER JOIN delicious_tags ON delicious_tags.link_id = $wpdb->links.link_id ";
		$wheres[] = "   tag IN (" . join(',', $tagConds) . ")";
		
		$sql .= " LEFT JOIN delicious_bookmarks ON $wpdb->links.link_id = delicious_bookmarks.link_id";
		
		$orderby = $delinks_ordering_info[delinks_get_orderby()]['sort_column'];
		$orderdir = delinks_get_orderdir();
	}
	else {
		$sql .= " LEFT JOIN delicious_bookmarks ON $wpdb->links.link_id = delicious_bookmarks.link_id";
		$orderby = "$wpdb->links.link_id";
		$orderdir = 'DESC';
		$limit = "LIMIT 0, 10";
	}
	
	$wheres[] = " $wpdb->links.link_visible = 'Y'";
	if(!empty($wheres))
		$sql .= " WHERE " . join(' AND ', $wheres);
	$sql .= " ORDER BY $orderby $orderdir";
	$sql .= ' ' . $limit;
	
	return $wpdb->get_results(
		$sql
	);
}


/**
 * Get the current page's link orderby sort order
 */
function delinks_get_orderdir(){
	global $delinks_ordering_info;
	static $orderdir = null;
	if($orderdir)
		return $orderdir;

	if(!empty($_GET['orderdir']) && ($_GET['orderdir'] == 'asc' || $_GET['orderdir'] == 'desc')){
		$orderdir = strtolower($_GET['orderdir']);
	}
	else {
		$orderdir = 'asc';
		foreach($delinks_ordering_info as $key => $orderinfo){
			if($key == delinks_get_orderby()){
				$orderdir = $orderinfo['orderdir'];
			}
		}
	}
	return $orderdir;
}


/**
 * Get the tags specified for a link; return as associated array, with tag as key and tag count as value
 */
function delinks_get_link_tags($link_id){
	global $wpdb;
	return $wpdb->get_results( $wpdb->prepare( "SELECT tag, count FROM delicious_tags WHERE link_id = %d ORDER BY count DESC", $link_id ) );
}

if(!function_exists('json_decode')){
	require_once(ABSPATH . '/prototypes/JSON.php');
	
	function json_encode($data) {
		static $json;
		if(!isset($json))
			$json = new Services_JSON();
		return( $json->encode($data) );
	}
	function json_decode($data) {
		static $json;
		if(!isset($json))
			$json = new Services_JSON();
		return( $json->decode($data) );
	}
}


/**
 * Update a link's info from Delicious; if no parameter is passed, it will look up the previous one that was done and do the next
 */
function delinks_update_link($link_id = 0){
	global $wpdb;
	
	
	//Get the next link that needs to be fetched
	$link_to_fetch = null;
	if(!$link_id){
		$prev_link_id = get_option('delinks_previous_link_id_fetched');
		$links = get_bookmarks(array(
			'hide_invisible' => false,
			'orderby' => 'id'
		));
		foreach($links as $link){
			if($link->link_id > $prev_link_id){
				$link_to_fetch = $link;
				break;
			}
		}
		if(!$link_to_fetch)
			$link_to_fetch = $links[0];
	
		//Remember which link was fetched so that next time the subsequent link will be fetched
		update_option('delinks_previous_link_id_fetched', $link_to_fetch->link_id);
	
		//Run this same cron in 11 minutes
		wp_schedule_single_event( time()+60*11, 'delinks_cron_update'); 
	}
	//Look up the provided link
	else {
		$link_to_fetch = get_bookmark($link_id);
	}
	if(!$link_to_fetch)
		return;
	
	$status = 500;
	if(function_exists('curl_init')){
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, "http://feeds.delicious.com/v2/json/urlinfo/" . md5($link_to_fetch->link_url));
		curl_setopt_array($ch, array(
			CURLOPT_HEADER => false,
			CURLOPT_REFERER => 'http://openscriptures.org/directory/',
			CURLOPT_RETURNTRANSFER => true
		));
		$urlinfo = curl_exec($ch);
		$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		curl_close($ch);
	}
	else {
		die('no CURL');
	}
	
	
	//Process the urlinfo
	if($status < 400){
		$urlinfo = json_decode($urlinfo);
		if(!empty($urlinfo)){
			//Update the delicious_bookmarks
			$res = $wpdb->query(
				$wpdb->prepare("REPLACE INTO delicious_bookmarks SET link_id = %d, post_count = %d",
							$link_to_fetch->link_id,
							$urlinfo[0]->total_posts
				)
			);
			
			//Update the tags for this bookmark: First delete all tags associated with the bookmark, and then add them back in
			$wpdb->query( $wpdb->prepare("DELETE FROM delicious_tags WHERE link_id = %d", $link_to_fetch->link_id) );
			if(!empty($urlinfo[0]->top_tags)){
				foreach($urlinfo[0]->top_tags as $tag => $count){
					$wpdb->query( $wpdb->prepare("INSERT INTO delicious_tags ( link_id, tag, count ) VALUES ( %d, %s, %d )",
						$link_to_fetch->link_id,
						$tag,
						$count
					) );
				}
			}
			
		}
		
	}
}
#add_action('init', 'delinks_update_link');
add_action('delinks_cron_update', 'delinks_update_link');
add_action('add_link', 'delinks_update_link');
add_action('edit_link', 'delinks_update_link');

/**
 * Get all of the tags associated with the query
 */
function delinks_get_tags($link_id = 0, $tags = array(), $orderby = 'tag', $orderdir = 'asc'){
	global $wpdb;
	
	if(empty($tags))
		$tags = get_query_var('delicious_tags');
	$sql = "SELECT tag, sum(count) as tag_count, count(*) as link_count FROM delicious_tags INNER JOIN $wpdb->links ON delicious_tags.link_id = $wpdb->links.link_id ";
	$wheres = array();
	#if($link_id)
	#	$wheres[] = " $wpdb->links.link_id = '" . mysql_real_escape_string($link_id) . "' ";
	$wheres[] = " $wpdb->links.link_visible = 'Y' ";
	if(!empty($tags)){
		$sqlTags = array();
		foreach($tags as $tag)
			$sqlTags[] = mysql_real_escape_string($tag);
		#$sql .= " WHERE tag IN ('" . join("', '", $sqlTags) . "')";
		$wheres[] = " tag IN ('" . join("', '", $sqlTags) . "')";
	}
	if(!empty($wheres))
		$sql .= " WHERE " . join(' AND ', $wheres);
	$sql .= " GROUP BY tag";
	$orderby = strtolower($orderby);
	if($orderby == 'tag' || $orderby == 'count')
		$orderby .= " ORDER BY $orderby ";
	if(strtolower($orderdir) == 'desc')
		$sql .= ' DESC';

	return $wpdb->get_results($sql);
}


/**
 * Clean up the database of all info related to a deleted link
 */
function delinks_cleanup_deleted_action($link_id){
	global $wpdb;
	$wpdb->query( $wpdb->prepare("DELETE FROM delicious_bookmarks WHERE link_id = %d", $link_id) );
	$wpdb->query( $wpdb->prepare("DELETE FROM delicious_tags WHERE link_id = %d", $link_id) );
}
add_action('delete_link', 'delinks_cleanup_deleted_action');


/**
 * This short code is inserted into the page that serves as the directory
 */
function delinks_shortcode($attrs, $content = null){
	global $wpdb;
	ob_start();
	
	$links = get_bookmarks(array(
		'hide_invisible' => true,
		'orderby' => 'id'
	));
	print "<pre>";
	foreach($links as $link){
		print $link->link_name . "\n";
		print "<a href='http://feeds.delicious.com/v2/rss/urlinfo/" . md5($link->link_url) . "'>$link->link_url</a>";
		print "\n\n";
	}
	print "</pre>";
	
	$output = ob_get_contents();
	ob_end_clean();
	return $output;
}
#add_shortcode('delicious_links', 'delinks_shortcode');


/**
 * Filter the page template path for the delinks_page_id
 */
function delinks_filter_page_template($path){
	global $wp_query;
	if($wp_query->post->ID == get_option('delinks_page_id')){
		return dirname(__FILE__) . '/page.php';
	}
	return $path;
}
add_filter('page_template', 'delinks_filter_page_template');

/**
 * Allow new query var for delicious_tags
 */
function delinks_add_query_var($public_query_vars) {
	$public_query_vars[] = 'delicious_tags';
	return $public_query_vars;
}
add_filter('query_vars', 'delinks_add_query_var');

/**
 * Turn the delicious_tags into an array
 */
function delinks_filter_request($vars){
	if(isset($vars['delicious_tags'])){
		if($vars['delicious_tags'])
			$vars['delicious_tags'] = preg_split('/\s+/', strtolower($vars['delicious_tags']));
		else
			$vars['delicious_tags'] = array();
	}
	return $vars;
}
add_filter('request', 'delinks_filter_request');


/**
 * Modify rewrite rules so that delinks_page_id can accept additional params /tag/[tags]/
 */
function delinks_filter_page_rewrite_rules($rules){
	$newRules = array();
	$newRules['(.+?)/tag/?(.+?)/?$'] = 'index.php?pagename=$matches[1]&delicious_tags=$matches[2]';
	foreach($rules as $k => $v){
		$newRules[$k] = $v;
	}
	//print "<pre>";
	//print_r($newRules);
	//print "</pre>";
	return $newRules;
}
add_filter('page_rewrite_rules', 'delinks_filter_page_rewrite_rules');




/**
 * Wrapper to add the links owners meta box
 */
function oss_links_owners_add_custom_box(){
    add_meta_box( 'oss_links_owners', 'Link Owners' , 'oss_links_owners_custom_box', 'link', 'normal' );
}
add_action('admin_menu', 'oss_links_owners_add_custom_box');


/**
 * Display the content of the links owners meta box
 */
function oss_links_owners_custom_box(){
	global $wpdb;
	global $link;
	?>
	<input type="hidden" name="delinks_noncename" id="delinks_noncename" value="<?php echo wp_create_nonce( plugin_basename(__FILE__) ) ?>" />
	<table cellspacing="2" cellpadding="5" style="width: 100%;" class="form-table">
		<tbody><tr class="form-field">
			<th valign="top" scope="row"><label for="link_owners">Link Owners</label><br /><small>Whitespace-delimited list of user names</small></th>
			<td>
				<label for='link_owners_all_available'>All Users: </label><select id='link_owners_all_available'><?php
				$users = $wpdb->get_results("SELECT * FROM $wpdb->users ORDER BY user_login"); #LEFT JOIN $wpdb->usermeta
				foreach($users as $user): ?>
					<option value='<?php echo htmlspecialchars($user->user_login) ?>'><?php
					echo htmlspecialchars($user->display_name != $user->user_login ? "$user->user_login ($user->display_name)": $user->display_name)
					?></option>
				<?php endforeach; ?></select><button type="button" id="link_owners_all_available_add">Add</button>
				<script>
				document.getElementById('link_owners_all_available').selectedIndex = -1;
				jQuery('#link_owners_all_available_add').click(function(e){
					e.preventDefault();
					var $ = jQuery;
					var $linkOwners = $('#link_owners');
					if($linkOwners.val())
						$linkOwners[0].value += ' ';
					if(!$('#link_owners_all_available').val())
						return;
					$linkOwners[0].value += $('#link_owners_all_available').val();
					//document.getElementById('link_owners_all_available').selectedIndex = -1;
					$('#link_owners_all_available').focus()[0].selectedIndex = -1;
				});
				</script>
				<textarea style="width: 95%;" id="link_owners" name="link_owners"><?php
				$users = $wpdb->get_col( $wpdb->prepare( "SELECT u.user_login FROM $wpdb->users u INNER JOIN oss_links_users os ON u.ID = os.user_id WHERE os.link_id = %d ORDER BY os.id", $link->link_id ) );
				print htmlspecialchars(join(' ', $users));
				?></textarea></td>
		</tr>
	</tbody></table>
	<?php
}

/**
 * Get the users that are associated with a link
 */
function delinks_get_link_owners($link_id){
	global $wpdb;
	#$wpdb->show_errors();
	return $wpdb->get_results( $wpdb->prepare("SELECT u.* FROM $wpdb->users u INNER JOIN oss_links_users os ON u.ID = os.user_id WHERE os.link_id = %d", $link_id) );
}


/**
 * Save the extra custom fields for the item
 */
function oss_links_save_link($link_id){
	global $wpdb;
	if (!isset($_POST['link_owners']) || !wp_verify_nonce( $_POST['delinks_noncename'], plugin_basename(__FILE__) )) {
		return $link_id;
	}

	$usernames = preg_split('/\s+/', trim($_POST['link_owners']));
	
	//Now delete all existing usermeta for this link_id
	$wpdb->query( $wpdb->prepare( "DELETE FROM oss_links_users WHERE link_id = %d", $link_id) );
	
	foreach($usernames as $username){
		$user_id = (int)$wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->users WHERE user_login = %s", $username ) );
		if(!$user_id)
			continue;
		$wpdb->query( $wpdb->prepare("INSERT INTO oss_links_users (link_id, user_id) VALUES (%d,%d)", $link_id, $user_id) );
	}
}
add_action('edit_link', 'oss_links_save_link');
add_action('add_link', 'oss_links_save_link');


/**
 * Make it so that the link description is a textarea with multiple paragraphs potentially
 */
function oss_links_make_description_textarea(){
	global $link;
	?>
	<script>
	jQuery(function($){
		var desc = document.getElementById('link_description');
		if(desc.nodeName.toLowerCase() != 'textarea'){
			var $textarea = $('<textarea name="link_description" rows="2" id="link_description" style="width:98%; height:47px;"></textarea>');
			$textarea.attr('tabindex', desc.tabIndex);
			$textarea.val(<?php echo json_encode($link->link_description) ?>);
			$(desc).replaceWith($textarea);
		}
	});
	</script>
	<?php
}
add_action('submitlink_box', 'oss_links_make_description_textarea');


